<template>
<section id="demos" class="invisible">
   <input type="file" ref="fileInput" @change="handleImageUpload" accept="image/*" class="file-input" />
    <div style="text-align: left;margin-bottom: 12px;">
         <button @click="triggerFileInput" class="upload-button" style="margin-right: 12px;">上传图片</button> 
         <button @click="detectFace"  class="upload-button" style="margin-right: 12px;">人脸识别</button> 
         <button @click="rotateImage" class="upload-button" style="margin-right: 12px;">旋转图片</button>
          <button @click="exportAvatar" class="upload-button">导出头像</button>
    </div>
  
    <div class="detectOnClick">
        <img  width="100%" crossorigin="anonymous" />
      
    </div>
</section>
</template>
<script setup lang="ts">
import {
  FaceDetector,
  FilesetResolver,
  Detection
} from "@mediapipe/tasks-vision";
import {ref, onMounted} from "vue";
let faceDetector: FaceDetector;
let runningMode: "IMAGE" ;
let detections: Detection[] = []; // 保存当前检测结果
let targetElement : HTMLImageElement;
const fileInput = ref<HTMLInputElement | null>(null);


onMounted(() => {
  targetElement = document.querySelector('.detectOnClick img') as HTMLImageElement;
  initializefaceDetector();
})

// Initialize the object detector
const initializefaceDetector = async () => {
  const vision = await FilesetResolver.forVisionTasks(
    "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm"
  );
  faceDetector = await FaceDetector.createFromOptions(vision, {
    baseOptions: {
      modelAssetPath: `https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite`,
      delegate: "GPU"
    },
    runningMode: runningMode
  });
  document.getElementById("demos").classList.remove("invisible");
};


const triggerFileInput = () => {
  if (fileInput.value) {
    fileInput.value.click();
  }
};

/**
 * Detect faces
 */
async function detectFace() {  // 移除了 event 参数
  // 检查是否有图片
  if (!targetElement || !targetElement.src || targetElement.src === window.location.href) {
    alert("请先上传一张图片");
    return;
  }

  removeHighlighters();

  if (!faceDetector) {
    console.log("Wait for objectDetector to load before clicking");
    return;
  }

  const ratio = targetElement.height / targetElement.naturalHeight;

  // faceDetector.detect returns a promise which, when resolved, is an array of Detection faces
  detections = faceDetector.detect(targetElement).detections;
  console.log(detections);

  displayImageDetections( targetElement);
}

function removeHighlighters() {
  const highlighters = targetElement.parentNode.getElementsByClassName(
    "highlighter"
  );
  while (highlighters[0]) {
    highlighters[0].parentNode.removeChild(highlighters[0]);
  }

  const infos = targetElement.parentNode.getElementsByClassName("info");
  while (infos[0]) {
    infos[0].parentNode.removeChild(infos[0]);
  }
  const keyPoints = targetElement.parentNode.getElementsByClassName("key-point");
  while (keyPoints[0]) {
    keyPoints[0].parentNode.removeChild(keyPoints[0]);
  }

}

function displayImageDetections(resultElement: HTMLElement) {
  const ratio = resultElement.height / resultElement.naturalHeight;
  console.log(ratio);

  for (let detection of detections) {
    // Description text
    const p = document.createElement("p");
    p.setAttribute("class", "info");
    p.innerText =
      "Confidence: " +
      Math.round(parseFloat(detection.categories[0].score) * 100) +
      "% .";
    // Positioned at the top left of the bounding box.
    // Height is whatever the text takes up.
    // Width subtracts text padding in CSS so fits perfectly.
    p.style =
      "left: " +
      detection.boundingBox.originX * ratio +
      "px;" +
      "top: " +
      (detection.boundingBox.originY * ratio - 30) +
      "px; " +
      "width: " +
      (detection.boundingBox.width * ratio - 10) +
      "px;" +
      "hight: " +
      20 +
      "px;";
    const highlighter = document.createElement("div");

    highlighter.setAttribute("class", "highlighter");
    highlighter.style =
      "left: " +
      detection.boundingBox.originX * ratio +
      "px;" +
      "top: " +
      detection.boundingBox.originY * ratio +
      "px;" +
      "width: " +
      detection.boundingBox.width * ratio +
      "px;" +
      "height: " +
      detection.boundingBox.height * ratio +
      "px;";

    resultElement.parentNode.appendChild(highlighter);
    resultElement.parentNode.appendChild(p);
    for (let keypoint of detection.keypoints) {
      const keypointEl = document.createElement("spam");
      keypointEl.className = "key-point";
      keypointEl.style.top = `${keypoint.y * resultElement.height - 3}px`;
      keypointEl.style.left = `${keypoint.x * resultElement.width - 3}px`;
      resultElement.parentNode.appendChild(keypointEl);
    }
  }
}

// 导出头像功能
function exportAvatar() {
  if (detections.length === 0) {
    alert("未检测到人脸");
    return;
  }

  // 使用第一个检测到的人脸
  const detection = detections[0];
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  // 计算头像区域
  const x = detection.boundingBox.originX;
  const y = detection.boundingBox.originY;
  const width = detection.boundingBox.width;
  const height = detection.boundingBox.height;
  
  // 设置canvas尺寸
  canvas.width = width;
  canvas.height = height;

   const imgElement = document.querySelector('.detectOnClick img') as HTMLImageElement;
  // 绘制头像区域到canvas
  ctx.drawImage(
    imgElement,
    x, y, width, height,  // 源区域
    0, 0, width, height   // 目标区域
  );
  
  // Create download link
  const link = document.createElement('a');
  link.download = 'avatar.png';
  link.href = canvas.toDataURL('image/png');
  link.click();
}
const rotationAngle = ref(0);
// 处理图片上传
function handleImageUpload(event) {
  const file = event.target.files[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = function(e) {
    const imgElement = document.querySelector('.detectOnClick img');
    imgElement.src = e.target.result as string;
    
    // 清除之前的检测结果
    const highlighters = imgElement.parentNode.getElementsByClassName("highlighter");
    while (highlighters[0]) {
      highlighters[0].parentNode.removeChild(highlighters[0]);
    }
    
    const infos = imgElement.parentNode.getElementsByClassName("info");
    while (infos[0]) {
      infos[0].parentNode.removeChild(infos[0]);
    }
    
    const keyPoints = imgElement.parentNode.getElementsByClassName("key-point");
    while (keyPoints[0]) {
      keyPoints[0].parentNode.removeChild(keyPoints[0]);
    }
    
    // 重置当前检测结果
    detections = [];
  };
  reader.readAsDataURL(file);
}

// 添加旋转图片函数
function rotateImage() {
  // 检查是否有图片
  if (!targetElement || !targetElement.src || targetElement.src === window.location.href) {
    alert("请先上传一张图片");
    return;
  }
  detections = [];
    removeHighlighters();

  const imgElement = targetElement;
  if (!imgElement || !imgElement.src) return;
  
  // 保存原始图片数据（如果是第一次旋转）
  // if (!originalImageSrc) {
  //   originalImageSrc = imgElement.src;
  // }
  
  // 计算新的旋转角度
  rotationAngle.value = (rotationAngle.value + 90) % 360;
  
  // 创建Canvas来处理图片旋转
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  // 根据旋转角度设置Canvas尺寸
  if (rotationAngle.value % 180 === 0) {
    canvas.width = imgElement.naturalWidth;
    canvas.height = imgElement.naturalHeight;
  } else {
    canvas.width = imgElement.naturalHeight;
    canvas.height = imgElement.naturalWidth;
  }
  
  // 清除画布
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 移动坐标系到画布中心
  ctx.translate(canvas.width / 2, canvas.height / 2);
  
  // 旋转画布
  ctx.rotate(rotationAngle.value * Math.PI / 180);
  
  // 绘制图片（注意坐标需要相应调整）
  ctx.drawImage(
    imgElement,
    -imgElement.naturalWidth / 2,
    -imgElement.naturalHeight / 2
  );
  
  // 将旋转后的图片更新到img元素
  imgElement.src = canvas.toDataURL('image/png');
  
  console.log('旋转角度:', rotationAngle.value);
  
}
</script>


<style >
.file-input {
  display: none;
}
section {
  opacity: 1;
  transition: opacity 500ms ease-in-out;
}

.mdc-button.mdc-button--raised.removed {
  display: none;
}

.invisible {
  opacity: 0.2;
}

.videoView,
.detectOnClick {
  position: relative;
  float: left;
  width: 48%;

  cursor: pointer;
  min-height: 200px;
  min-width: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px dashed #ccc;
}

.detectOnClick p {
  position: absolute;
  padding: 5px;
  background-color: #007f8b;
  color: #fff;
  border: 1px dashed rgba(255, 255, 255, 0.7);
  z-index: 2;
  font-size: 12px;
  margin: 0;
}

.videoView p {
  position: absolute;
  padding-bottom: 5px;
  padding-top: 5px;
  background-color: #007f8b;
  color: #fff;
  border: 1px dashed rgba(255, 255, 255, 0.7);
  z-index: 2;
  font-size: 12px;
  margin: 0;
}

.highlighter {
  background: rgba(0, 255, 0, 0.25);
  border: 1px dashed #fff;
  z-index: 1;
  position: absolute;
}


.detectOnClick {
  z-index: 0;
}

.detectOnClick img {
  width: 100%;
}
.key-point {
  position: absolute;
  z-index: 1;
  width: 3px;
  height: 3px;
  background-color: #ff0000;
  /* border: 1px solid #ffffff; */
  border-radius: 50%;
  display: block;
}
</style>
